using libC;
using libC.translate;
using System;
using System.Collections.Generic;
using System.IO;

namespace wrapCLI
{
    internal class Program
    {
        private const string HELP_COMM = "?";           //帮助
        private const string VERSION_COMM = "-v";       //版本
        private const string GEN_COMM = "-g";           //生成wrap
        private const string FILE_NAME_COMM = "-n";     //wrap文件名
        private const string NAME_SPACE_COMM = "-s";    //命名空间名
        private const string FORCE_COMM = "-f";         //强安全模式

        private static List<string> commandTips = new List<string>() {
            "命令列表:",
            $"[{HELP_COMM}] : 打印帮助信息",
            $"[{VERSION_COMM}] : 版本信息",
            $"[{GEN_COMM}] [语言] [源目录] [输出目录] [动态库文件路径] : 通过指定的C项目目录生成wrap代码.",
            $"[{FILE_NAME_COMM}] : wrap生成的代码和文件命名.",
            $"[{NAME_SPACE_COMM}] : 代码类添加命名空间名（C# 有效）.",
            $"[{FORCE_COMM}] : 强制安全模式，用户必须修改不符合约定的声明.",
            "",
            "命令细节说明:",
            "-g {",
            "   [语言] : 生成wrap语言，可选 [c] [c#]",
            "   [源目录] : C项目目录路径字符串",
            "   [输出目录] : wrap代码输出目录路径",
            "   [动态库文件路径] : 动态库文件路径",
            "}",
        };

        private static int cBuoy = 0;
        private static Dictionary<string, List<string>> commandDic = new Dictionary<string, List<string>>();

        static void Main(string[] args)
        {
            //test
            //args = new string[] {
            //    "?",
            //    "-v",
            //    "-g",
            //    "c",
            //    "./xxx/",
            //    "./xxx/",
            //    "./xxx.dll",
            //    "-fn",
            //    "oixx",
            //    "-ns",
            //    "nnnna",
            //};

            //读取命令
            commandStreamRead(args);
            //执行命令
            commandAct();
        }

        private static void commandStreamRead(string[] args)
        {
            if (cBuoy >= args.Length) return;
            //命令
            string hCom = args[cBuoy];
            cBuoy++;
            if (!commandDic.ContainsKey(hCom))
            {
                commandDic[hCom] = new List<string>();
            }
            //命令参数
            while (cBuoy < args.Length)
            {
                string cParam = args[cBuoy];
                string _hStr = cParam.Substring(0, 1);
                if (_hStr == "-" || _hStr == "?") break;
                commandDic[hCom].Add(cParam);
                cBuoy++;
            }

            //continue reading
            commandStreamRead(args);
        }


        private static void commandAct()
        {
            foreach (var item in commandDic)
            {
                switch (item.Key)
                {
                    case GEN_COMM: wrapGenerate(item.Value.ToArray()); break;
                    case HELP_COMM: printTip(); break;
                    case VERSION_COMM: printVer(); break;
                }
            }
        }


        private static void printTip()
        {
            foreach (var item in commandTips)
            {
                Console.WriteLine($"{item}\n");
            }
        }

        private static void printVer()
        {
            Console.WriteLine($"V{libC.Version.ver}\n");
        }

        private static void wrapGenerate(string[] args)
        {
            if (args.Length < 4)
            {
                if (args.Length < 1)
                    Console.WriteLine("没有输入 [语言] 参数");
                else if (args.Length < 2)
                    Console.WriteLine("没有输入 [源目录] 参数");
                else if (args.Length < 3)
                    Console.WriteLine("没有输入 [输出目录] 参数");
                else
                    Console.WriteLine("没有输入 [动态库文件路径] 参数");
                return;
            }
            //
            string langStr = args[0];
            string srcPath = args[1];
            string outPath = args[2];
            string dllPath = args[3];

            string wrapName = "";
            if (commandDic.ContainsKey(FILE_NAME_COMM))
            {
                var _list = commandDic[FILE_NAME_COMM];
                if (_list.Count < 1)
                    Console.WriteLine($"{FILE_NAME_COMM}命令 没有输入有效 wrap文件名 参数");
                else
                    wrapName = _list[0];
            }
            string nameSpace = "";
            if (commandDic.ContainsKey(NAME_SPACE_COMM))
            {
                var _list = commandDic[NAME_SPACE_COMM];
                if (_list.Count < 1)
                    Console.WriteLine($"{NAME_SPACE_COMM}命令 没有输入有效 命名空间名 参数");
                else
                    nameSpace = _list[0];
            }
            bool forceSafe = commandDic.ContainsKey(FORCE_COMM) ? true : false;

            if (!Directory.Exists(srcPath))
            {
                Console.WriteLine(" 源目录路径 不存在！");
                return;
            }

            if (!Directory.Exists(outPath))
            {
                //Console.WriteLine(" 输出目录路径 不存在！");
                //return;
                Directory.CreateDirectory(outPath);
            }

            string wrapFileName = wrapName != "" ? wrapName : "wrap";
            var semAnaly = tools.getSemAnalyByProj(srcPath);
            semAnaly.parse();
            switch (langStr)
            {
                case "c":
                    //C wrap code gen
                    string c_codeStr = wrapCodeGenerator.codeGen(semAnaly, wrapLang.C, dllPath, wrapName, nameSpace);
                    //拆分 code， h_codeStr.Split("fdsfsf");
                    var codes = c_codeStr.Split(tools.CODESPLITE);
                    //保存 .h code
                    File.WriteAllText($"{outPath}{wrapFileName}.h", codes[0]);
                    //保存 .h code
                    File.WriteAllText($"{outPath}{wrapFileName}.cpp", codes[1]);
                    break;
                case "c#":
                    //C# wrap code gen
                    string cs_codeStr = wrapCodeGenerator.codeGen(semAnaly, wrapLang.C_SHARP, dllPath, wrapName, nameSpace, forceSafe);
                    wrapFileName += ".cs";
                    File.WriteAllText($"{outPath}{wrapFileName}", cs_codeStr);
                    break;
            }
        }
    }
}
